#include "UamMsgProcess.h"

#include <core/Utility.h>
#include <core/time/time.h>
#include <qbkernel/include/qb_base.h>
#include <qbprotocol/include/MessageParser.h>
#include <qbprotocol/include/MessageParserTool.h>
#include <qbprotocol/include/SSQBModel.h>
#include <qbprotocol/include/rdProto.h>

#ifdef _MSC_VER
#pragma comment(lib, "ws2_32.lib")
#endif

using namespace qb;
#define Reg_Func(ID) \
  qb::qbBase::getMessageBond()->RegisterDecodeFunc(ID, uam::ExtracFunc)
#define DelPtr(FUNC, TYPE)               \
  case FUNC: {                           \
    TYPE* p = static_cast<TYPE*>(toDel); \
    delete p;                            \
    return nullptr;                      \
  } break;

namespace uam {
void* delAck(int func, void* toDel) {
  switch (func) {
    DelPtr(E_FID_QB_ALL_CMPY_QRY, xQBTradeCmpyInfoListAck_c);
    DelPtr(E_FID_QB_FLAGS_REQ, xQBFlagsAck_c);
    DelPtr(E_FID_QB_GLOBAL_SWITCH, xQBGlobalSwitchAck_t);
    DelPtr(E_FID_QB_QUERY_NEW_UERINFO_REQ, QBAccountInfoNewAck_t);
    DelPtr(E_FID_QB_USEPROTOCAL_QUERY_REQ, QBUseProtocolQueryAck);
    DelPtr(E_FID_QB_USER_MEMBER_INFO_REQ, xUserMemberInfoAck_c);
    DelPtr(E_FID_QB_AUTHORITY_QUERY_NEW_REQ, xQBAuthorityQueryAck_c);
    DelPtr(E_FID_QB_MOBILE_VERIFY_INFO, xQBMobileVerifyInfoAck_c);
    DelPtr(E_FID_QB_CONDITION_GRUOP_REQ_NEW, xQBConditionGroupReqNew);
    DelPtr(E_FID_SIGNAL, xSignalInfo_t);
    default:
      break;
  }
  return toDel;
}
void* ExtracFunc(int func, const ProtoMessage& msg, void* toDel) {
  if (toDel != nullptr) return delAck(func, toDel);

  void* data = nullptr;
  switch (func) {
    case E_FID_QB_ALL_CMPY_QRY: {
      ProtoList msglist;
      if (!msg.getList("List", msglist)) return nullptr;

      xQBTradeCmpyInfoListAck_c* ptr = new xQBTradeCmpyInfoListAck_c();
      data = ptr;
      xQBTradeCmpyInfo_c tradeinfo_unit;

      for (ProtoList::const_iterator it = msglist.begin(); it != msglist.end();
           ++it) {
        if (it->Type != ProtoValue::VAR_MAP) continue;

        memset(&tradeinfo_unit, 0, sizeof(xQBTradeCmpyInfo_c));
        const ProtoMap& msgmap = *it;

        bool bret = msgmap.GetInt32("Id", tradeinfo_unit.m_Id);
        if (!bret) continue;  // 以防错误的数据
        FIELDCOPY(tradeinfo_unit.m_Name,
                  CParserTool::GetString(msgmap, "Name"));
        FIELDCOPY(tradeinfo_unit.m_Code,
                  CParserTool::GetString(msgmap, "Code"));
        FIELDCOPY(tradeinfo_unit.m_EnName,
                  CParserTool::GetString(msgmap, "EnName"));
        FIELDCOPY(tradeinfo_unit.m_FullName,
                  CParserTool::GetString(msgmap, "FullName"));

        FIELDCOPY(tradeinfo_unit.m_Address,
                  CParserTool::GetString(msgmap, "Address"));
        FIELDCOPY(tradeinfo_unit.m_PostCode,
                  CParserTool::GetString(msgmap, "PostCode"));
        FIELDCOPY(tradeinfo_unit.m_Tel, CParserTool::GetString(msgmap, "Tel"));
        FIELDCOPY(tradeinfo_unit.m_Fax, CParserTool::GetString(msgmap, "Fax"));
        FIELDCOPY(tradeinfo_unit.m_Email,
                  CParserTool::GetString(msgmap, "Email"));

        ptr->m_List.push_back(tradeinfo_unit);
      }

      xQBTradeCmpContact_c contact_unit;
      if (msg.GetList("ContactList", msglist)) {
        for (ProtoList::const_iterator it = msglist.begin();
             it != msglist.end(); ++it) {
          if (it->Type != ProtoValue::VAR_MAP) continue;

          memset(&contact_unit, 0, sizeof(xQBTradeCmpContact_c));
          const ProtoMap& msgmap = *it;

          msgmap.GetInt32("ID", contact_unit.m_ID);
          msgmap.GetInt32("CompanyId", contact_unit.m_CompanyId);
          FIELDCOPY(contact_unit.m_Contact,
                    CParserTool::GetString(msgmap, "Contact"));
          FIELDCOPY(contact_unit.m_EName,
                    CParserTool::GetString(msgmap, "EName"));
          FIELDCOPY(contact_unit.m_TEL, CParserTool::GetString(msgmap, "TEL"));
          FIELDCOPY(contact_unit.m_Dept,
                    CParserTool::GetString(msgmap, "Dept"));
          FIELDCOPY(contact_unit.m_QM, CParserTool::GetString(msgmap, "QM"));
          FIELDCOPY(contact_unit.m_QQ, CParserTool::GetString(msgmap, "QQ"));
          FIELDCOPY(contact_unit.m_MSN, CParserTool::GetString(msgmap, "MSN"));
          FIELDCOPY(contact_unit.m_RM, CParserTool::GetString(msgmap, "RM"));
          FIELDCOPY(contact_unit.m_QQEnterprise,
                    CParserTool::GetString(msgmap, "QQEnterprise"));

          ptr->m_ContactList.push_back(contact_unit);
        }
      }

      msg.GetInt32("SaveType", ptr->m_SaveType);
    } break;
    case E_FID_QB_FLAGS_REQ: {
      xQBFlagsAck_c* pFlags = new xQBFlagsAck_c();
      data = pFlags;

      FIELDCOPY(pFlags->m_CompanyID, CParserTool::GetString(msg, "CompanyID"));
      FIELDCOPY(pFlags->m_UserId, CParserTool::GetString(msg, "UserID"));

      ProtoList sublist;
      if (!msg.GetList("List", sublist)) return nullptr;
      for (ProtoList::const_iterator it = sublist.begin(); it != sublist.end();
           ++it) {
        const ProtoMap& msgmap = *it;
        char szKey[64] = {0};
        char szVal[1024] = {0};
        FIELDCOPY(szKey, CParserTool::GetString(msgmap, "Key"));
        FIELDCOPY(szVal, CParserTool::GetString(msgmap, "Value"));

        pFlags->listFlags.push_back(xQbFlag_c(szKey, szVal));
      }
    } break;
    case E_FID_QB_GLOBAL_SWITCH: {
      xQBGlobalSwitchAck_t* ptr = new xQBGlobalSwitchAck_t();
      data = ptr;
      FIELDCOPY(ptr->m_Version, CParserTool::GetString(msg, "Version"));
      FIELDCOPY(ptr->m_UserID, CParserTool::GetString(msg, "UserID"));

      ProtoList msglist;
      if (!msg.getList("Flags", msglist)) {
        delete ptr;
        return nullptr;
      }

      char skey[64] = {0};
      char svalue[512] = {0};
      for (ProtoList::const_iterator it = msglist.begin(); it != msglist.end();
           ++it) {
        if (it->Type != ProtoValue::VAR_MAP) continue;
        const ProtoMap& msgmap = *it;
        memset(skey, 0, sizeof(skey));
        memset(svalue, 0, sizeof(svalue));
        FIELDCOPY(skey, CParserTool::GetString(msgmap, "Key"));
        FIELDCOPY(svalue, CParserTool::GetString(msgmap, "Value"));

        if (strlen(skey) > 0 && strlen(svalue) > 0) {
          ptr->m_Flags[skey] = svalue;
          log_debug("GlobalVarible [%s] = (%s)", skey, svalue);
        }
      }

    } break;
    case E_FID_QB_QUERY_NEW_UERINFO_REQ: {
      QBAccountInfoNewAck_t* ptr = new QBAccountInfoNewAck_t();
      data = ptr;
      FIELDCOPY(ptr->m_UserId, CParserTool::GetString(msg, "UserId"));
      FIELDCOPY(ptr->m_Password, CParserTool::GetString(msg, "Password"));
      FIELDCOPY(ptr->m_UserName, CParserTool::GetString(msg, "UserName"));
      FIELDCOPY(ptr->m_DisplayName, CParserTool::GetString(msg, "DisplayName"));
      const char* str = 0;
      size_t len = 0;
      if (msg.RefString("DisplayName", str, len) && str && len > 0) {
        if (len > _countof(ptr->m_DisplayName_Utf8))
          len = _countof(ptr->m_DisplayName_Utf8) - 1;
#ifdef _MSC_VER
        strncpy_s(ptr->m_DisplayName_Utf8, _countof(ptr->m_DisplayName_Utf8),
                  str ? str : "", len);
#else
        strncpy(ptr->m_DisplayName_Utf8, str ? str : "", len);
#endif
      }
      FIELDCOPY(ptr->m_CompanyId, CParserTool::GetString(msg, "CompanyId"));
      FIELDCOPY(ptr->m_CompanyName, CParserTool::GetString(msg, "CompanyName"));
      FIELDCOPY(ptr->m_AccountType, CParserTool::GetString(msg, "AccountType"));
      FIELDCOPY(ptr->m_ExpireDate, CParserTool::GetString(msg, "ExpireDate"));
      FIELDCOPY(ptr->m_Telephone, CParserTool::GetString(msg, "Telephone"));
      FIELDCOPY(ptr->m_Mobile, CParserTool::GetString(msg, "Mobile"));
      FIELDCOPY(ptr->m_Rm, CParserTool::GetString(msg, "Rm"));
      FIELDCOPY(ptr->m_Msn, CParserTool::GetString(msg, "Msn"));
      FIELDCOPY(ptr->m_QQ, CParserTool::GetString(msg, "QQ"));
      FIELDCOPY(ptr->m_Address, CParserTool::GetString(msg, "Address"));
      FIELDCOPY(ptr->m_Department, CParserTool::GetString(msg, "Department"));
      FIELDCOPY(ptr->m_BussinessType,
                CParserTool::GetString(msg, "BussinessType"));
      FIELDCOPY(ptr->m_Title, CParserTool::GetString(msg, "Title"));
      FIELDCOPY(ptr->m_QQEnterprise,
                CParserTool::GetString(msg, "QQEnterprise"));
      FIELDCOPY(ptr->m_QQEnterprise_Company,
                CParserTool::GetString(msg, "QQEnterprise_Company"));
      char* pos = strchr(ptr->m_ExpireDate, ' ');
      if (pos) ptr->m_ExpireDate[pos - ptr->m_ExpireDate] = '\0';

      ProtoList msglist;
      if (msg.getList("lstPhone", msglist)) {
        ProtoMap submsg;
        for (ProtoList::const_iterator it = msglist.begin();
             it != msglist.end(); ++it) {
          if (it->Type != ProtoValue::VAR_MAP) continue;
          const ProtoMap& msgmap = *it;
          xQBAccountInfoNewAckUnit unit;
          FIELDCOPY(unit.m_Type, CParserTool::GetString(msgmap, "Type"));
          FIELDCOPY(unit.m_Phone, CParserTool::GetString(msgmap, "Phone"));
          ptr->m_lstPhone.push_back(unit);
        }
      }
    } break;
    case E_FID_QB_USEPROTOCAL_QUERY_REQ: {
      QBUseProtocolQueryAck* ptr = new QBUseProtocolQueryAck();
      data = ptr;
      FIELDCOPY(ptr->m_UserId, CParserTool::GetString(msg, "UserId"));
      FIELDCOPY(ptr->m_UserAccount, CParserTool::GetString(msg, "UserAccount"));
      FIELDCOPY(ptr->m_UserName, CParserTool::GetString(msg, "UserName"));
      FIELDCOPY(ptr->m_InstitutionID,
                CParserTool::GetString(msg, "InstitutionID"));
      FIELDCOPY(ptr->m_InstitutionName,
                CParserTool::GetString(msg, "InstitutionName"));
    } break;
    case E_FID_QB_USER_MEMBER_INFO_REQ: {
      xUserMemberInfoAck_c* userMemberInfo = new xUserMemberInfoAck_c();
      data = userMemberInfo;
      FIELDCOPY(userMemberInfo->m_UserId,
                CParserTool::GetString(msg, "UserId"));
      FIELDCOPY(userMemberInfo->m_UserAccount,
                CParserTool::GetString(msg, "UserAccount"));
      FIELDCOPY(userMemberInfo->m_CompanyId,
                CParserTool::GetString(msg, "CompanyId"));
      FIELDCOPY(userMemberInfo->m_MemberLevel,
                CParserTool::GetString(msg, "MemberLevel"));
      FIELDCOPY(userMemberInfo->m_IsPaidCustom,
                CParserTool::GetString(msg, "IsPaidCustom"));
      msg.GetInt32("CurrentMonthBp", userMemberInfo->m_CurrentMonthBp);
      msg.GetInt32("TotalBp", userMemberInfo->m_TotalBp);
      msg.GetInt32("OpenPageBpCanGetToday",
                   userMemberInfo->m_OpenPageBpCanGetToday);
      FIELDCOPY(userMemberInfo->m_FirstLogInReceived,
                CParserTool::GetString(msg, "FirstLogInReceived"));
      FIELDCOPY(userMemberInfo->m_FirstOpenRecommendReceived,
                CParserTool::GetString(msg, "FirstOpenRecommendReceived"));

      ProtoList sublist;
      if (msg.GetList("ListLevel", sublist)) {
        for (ProtoList::const_iterator it = sublist.begin();
             it != sublist.end(); ++it) {
          const ProtoMap& msgmap = *it;
          sUserMemberLevelList levelUnit;
          msgmap.GetInt32("Level", levelUnit.m_Level);
          msgmap.GetInt32("MinBp", levelUnit.m_MinBp);
          userMemberInfo->m_ListLevel.push_back(levelUnit);
        }
      }
    } break;
    case E_FID_QB_AUTHORITY_QUERY_NEW_REQ: {
      xQBAuthorityQueryAck_c* ptr = new xQBAuthorityQueryAck_c();
      data = ptr;
      FIELDCOPY(ptr->m_UserId, CParserTool::GetString(msg, "UserId"));
      FIELDCOPY(ptr->m_OverSeaFlag, CParserTool::GetString(msg, "OverSeaFlag"));
      msg.getInt32("AllowOpenQM", ptr->m_AllowOpenQM);
      msg.getInt32("AllowAlltab", ptr->m_AllowAlltab);
      msg.getInt32("AllowMarketStream", ptr->m_AllowMarketStream);

      ProtoList msglist;
      if (msg.getList("BusinessList", msglist)) {
        for (ProtoList::const_iterator it = msglist.begin();
             it != msglist.end(); ++it) {
          if (it->Type != ProtoValue::VAR_MAP) continue;

          const ProtoMap& msgmap = *it;
          xQBAuthorityBusiness_c businessUnit;
          FIELDCOPY(businessUnit.m_BrokerID,
                    CParserTool::GetString(msgmap, "BrokerID"));
          FIELDCOPY(businessUnit.m_BrokerName,
                    CParserTool::GetString(msgmap, "BrokerName"));
          FIELDCOPY(businessUnit.m_CompanyType,
                    CParserTool::GetString(msgmap, "CompanyType"));
          FIELDCOPY(businessUnit.m_AllowName,
                    CParserTool::GetString(msgmap, "AllowName"));
          FIELDCOPY(businessUnit.m_AllowNameEn,
                    CParserTool::GetString(msgmap, "AllowNameEn"));
          FIELDCOPY(businessUnit.m_Abbr,
                    CParserTool::GetString(msgmap, "abbr"));
          FIELDCOPY(businessUnit.m_BusinessAllowId,
                    CParserTool::GetString(msgmap, "BusinessAllowId"));
          FIELDCOPY(businessUnit.m_AllowName,
                    CParserTool::GetString(msgmap, "AllowName"));
          FIELDCOPY(businessUnit.m_AllowNameEn,
                    CParserTool::GetString(msgmap, "AllowNameEn"));
          FIELDCOPY(businessUnit.m_BusinessName,
                    CParserTool::GetString(msgmap, "BusinessName"));
          FIELDCOPY(businessUnit.m_BusinessCode,
                    CParserTool::GetString(msgmap, "BusinessCode"));
          FIELDCOPY(businessUnit.m_BusinessLevel,
                    CParserTool::GetString(msgmap, "BusinessLevel"));
          FIELDCOPY(businessUnit.m_Email,
                    CParserTool::GetString(msgmap, "Email"));
          FIELDCOPY(businessUnit.m_UserName,
                    CParserTool::GetString(msgmap, "UserName"));
          FIELDCOPY(businessUnit.m_ContactName,
                    CParserTool::GetString(msgmap, "ContactName"));
          FIELDCOPY(businessUnit.m_ContactTEL,
                    CParserTool::GetString(msgmap, "ContactTEL"));
          msgmap.getInt32("Status_C", businessUnit.m_Status_C);
          msgmap.getInt32("Status_T", businessUnit.m_Status_T);
          msgmap.getInt32("Status_B", businessUnit.m_Status_B);

          // sub list
          ProtoList msgsublist;
          if (msgmap.getList("BrokerList", msgsublist)) {
            for (ProtoList::const_iterator iit = msgsublist.begin();
                 iit != msgsublist.end(); ++iit) {
              if (iit->Type != ProtoValue::VAR_MAP) continue;
              const ProtoMap& submsgmap = *iit;
              xQBAuthorityBroker_c BrokerUnit;
              FIELDCOPY(BrokerUnit.m_UserName,
                        CParserTool::GetString(submsgmap, "UserName"));
              FIELDCOPY(BrokerUnit.m_DisplayName,
                        CParserTool::GetString(submsgmap, "DisplayName"));
              FIELDCOPY(BrokerUnit.m_Mobile,
                        CParserTool::GetString(submsgmap, "Mobile"));
              FIELDCOPY(BrokerUnit.m_Department,
                        CParserTool::GetString(submsgmap, "Department"));
              FIELDCOPY(BrokerUnit.m_TEL,
                        CParserTool::GetString(submsgmap, "TEL"));
              FIELDCOPY(BrokerUnit.m_Email,
                        CParserTool::GetString(submsgmap, "Email"));

              businessUnit.m_BrokerList.push_back(BrokerUnit);
            }
          }
          ptr->m_BusinessList.push_back(businessUnit);
        }
      }

      if (msg.getList("ItemList", msglist)) {
        for (ProtoList::const_iterator it = msglist.begin();
             it != msglist.end(); ++it) {
          if (it->Type != ProtoValue::VAR_MAP) continue;

          const ProtoMap& msgmap = *it;
          xLevelItem_c levelItem;
          FIELDCOPY(levelItem.m_BusinessLevel,
                    CParserTool::GetString(msgmap, "BusinessLevel"));
          FIELDCOPY(levelItem.m_ItemKey,
                    CParserTool::GetString(msgmap, "ItemKey"));
          FIELDCOPY(levelItem.m_Value, CParserTool::GetString(msgmap, "Value"));
          FIELDCOPY(levelItem.m_PriceType,
                    CParserTool::GetString(msgmap, "PriceType"));
          FIELDCOPY(levelItem.m_MemoFlag,
                    CParserTool::GetString(msgmap, "MemoFlag"));

          ptr->m_ItemList.push_back(levelItem);
        }
      }
    } break;
    case E_FID_QB_MOBILE_VERIFY_INFO: {
      xQBMobileVerifyInfoAck_c* ptr = new xQBMobileVerifyInfoAck_c();
      data = ptr;
      FIELDCOPY(ptr->m_mobile, CParserTool::GetString(msg, "mobile"));
      FIELDCOPY(ptr->m_time, CParserTool::GetString(msg, "time"));
      msg.GetBool("verifyMobile", ptr->m_verifyMobile);
      msg.GetInt32("restTimes", ptr->m_restTimes);
      msg.GetInt32("verifyHour", ptr->m_verifyHour);
    } break;
    case E_FID_QB_CONDITION_GRUOP_REQ_NEW: {
      xQBConditionGroupList_c* ptr = new xQBConditionGroupList_c();
      data = ptr;

      ProtoList msglist;
      if (msg.getList("List", msglist)) {
        for (ProtoList::const_iterator it = msglist.begin();
             it != msglist.end(); ++it) {
          if (it->Type != ProtoValue::VAR_MAP) continue;

          xQBConditionGroupUnit_c conditiongroup_unit;
          conditiongroup_unit.m_ConditionGroupId[0] = '\0';
          conditiongroup_unit.m_ConditionGroupName[0] = '\0';
          conditiongroup_unit.m_ConditionBuf[0] = '\0';
          conditiongroup_unit.m_Time = 0;
          conditiongroup_unit.m_SortID = 0;
          const ProtoMap& msgmap = *it;

          FIELDCOPY(conditiongroup_unit.m_ConditionGroupId,
                    CParserTool::GetString(msgmap, "ConditionGroupId"));
          FIELDCOPY(conditiongroup_unit.m_ConditionGroupName,
                    CParserTool::GetString(msgmap, "ConditionGroupName"));
          FIELDCOPY(conditiongroup_unit.m_ConditionBuf,
                    CParserTool::GetString(msgmap, "ConditionBuf"));

          qb::base::HighResTime timer;
          MessageParser mPaser;
          if (mPaser.DecodeFilterMessage(
                  conditiongroup_unit.m_ConditionBuf,
                  strlen(conditiongroup_unit.m_ConditionBuf),
                  conditiongroup_unit.m_BondFilter) <= 0) {
            log_error(
                "解析消息E_FID_QB_CONDITION_GRUOP_REQ_NEW的m_"
                "ConditionBuf出现错误,忽略,id:%s name:%s ",
                conditiongroup_unit.m_ConditionGroupId,
                conditiongroup_unit.m_ConditionGroupName);
            continue;
          }
          log_debug("[filter] DecodeFilterMessage last:%8dus id:%s name:%s",
                    timer.elapsed().microsec(),
                    conditiongroup_unit.m_ConditionGroupId,
                    conditiongroup_unit.m_ConditionGroupName);

          CParserTool::MessageGetTime(msgmap, "Time",
                                      conditiongroup_unit.m_Time);
          msgmap.GetInt32("SortID", conditiongroup_unit.m_SortID);

          ptr->m_List.push_back(conditiongroup_unit);
        }
      }
    } break;
    case E_FID_SIGNAL: {
      ProtoList msglist;
      if (!msg.getList("IMQ_OUTCOME", msglist)) return nullptr;

      xSignalInfo_t* ptr = new xSignalInfo_t;
      data = ptr;
      ProtoMap submsg;
      for (ProtoList::const_iterator it = msglist.begin(); it != msglist.end();
           ++it) {
        if (it->Type != ProtoValue::VAR_MAP) continue;

        memset(ptr, 0, sizeof(xSignalInfo_t));
        const ProtoMap& msgmap = *it;
        FIELDCOPY(ptr->m_info, CParserTool::GetString(msgmap, "sync"));
        break;  // 一次只发一种信号，故break
      }
    } break;
    default:
      break;
  }

  return data;
}

void InitDecodeFuncs() {
  Reg_Func(E_FID_QB_ALL_CMPY_QRY);
  Reg_Func(E_FID_QB_FLAGS_REQ);
  Reg_Func(E_FID_QB_GLOBAL_SWITCH);
  Reg_Func(E_FID_QB_QUERY_NEW_UERINFO_REQ);
  Reg_Func(E_FID_QB_USEPROTOCAL_QUERY_REQ);
  Reg_Func(E_FID_QB_USER_MEMBER_INFO_REQ);
  Reg_Func(E_FID_QB_AUTHORITY_QUERY_NEW_REQ);
  Reg_Func(E_FID_QB_MOBILE_VERIFY_INFO);
  Reg_Func(E_FID_QB_CONDITION_GRUOP_REQ_NEW);
  Reg_Func(E_FID_SIGNAL);
}

}  // namespace uam
